#include <iostream>
#include <fstream>
#include "curve_fit.h"
#include <cmath>
#include <algorithm>
#include <vector>
#include <jsoncpp/json/json.h>
using namespace std;

class Fun1 : public Function
{
public:
    double operator () (double x)
	{
	    if(x>=0 && x<=sqrt(3)){
		return 2.0/3.0*(sqrt(x)+sqrt(3-x*x));
	    }else if(x<0 && x>=-sqrt(3)){
		return 2.0/3.0*(sqrt(-x)+sqrt(3-x*x));
	    }else{
		return 0;
	    }
	}
    double diff()
    {
        return 0;
    }
    double diff2()
    {
        return 0;
    }
    
};

class Fun2 : public Function
{
public:
    double operator () (double x) 
	{
	    if(x>=0 && x<=sqrt(3)){
		return 2.0/3.0*(sqrt(x)-sqrt(3-x*x));
	    }else if(x<0 && x>=-sqrt(3)){
		return 2.0/3.0*(sqrt(-x)-sqrt(3-x*x));
	    }else{
		return 0;
	    }
	}

    double diff()
    {
        return 0;
    }
    double diff2()
    {
        return 0;
    }
    
};

int main()
{
    Fun1 f1;
    Fun2 f2;
    Json::Reader reader;
    Json::Value root;
    std::ofstream fout1,fout2;

    std::ifstream in("./date/input/E.json", std::ios::binary);
    if (!in.is_open())
    {
	std::cout << "error: cannot open file." << std::endl;
	return -1;
    }

    std::vector<int> point_Num;

    if (reader.parse(in, root))
	{
        for (int i = 0; i < root["n"].size(); i++)
	    {
	        int temp_n = root["n"][i].asInt();
	        point_Num.push_back(temp_n);
	    }
    }
 

    fout1.open("proE_BForm_points.txt");
    fout2.open("proE_PPForm_points.txt");


/**
 * 生成表示曲线的散点 zhiquyibufen
*/
    for (int i = 0; i < point_Num.size(); i++)
	{
        std::vector<std::vector<double> > Points;
        std::vector<double> P_tmp;

        int num_1 = floor((point_Num[i]- 4.0)/4.0);   //y >0
        int num_2 = floor((point_Num[i]- 4.0)/2.0) - num_1;  //y<0

        P_tmp.push_back(0.0);
        P_tmp.push_back(sqrt(3.0)*2.0/3.0);

        Points.push_back(P_tmp);
        P_tmp.clear();

        for (int j = 1; j <= num_1; j++)
		{
            double x = j*sqrt(3.0)/(num_1+1.0);
            P_tmp.push_back(x);
            P_tmp.push_back(f1(x));
            Points.push_back(P_tmp);
            P_tmp.clear();
		}

        P_tmp.push_back(sqrt(3.0));
        P_tmp.push_back(sqrt(sqrt(3.0))*2.0/3.0);
        Points.push_back(P_tmp);
        P_tmp.clear();

        for (int j = 1; j <= num_2; j++)
		{
            double x = sqrt(3.0) - j*sqrt(3.0)/(num_2+1.0);
            P_tmp.push_back(x);
            P_tmp.push_back(f2(x));
            Points.push_back(P_tmp);
            P_tmp.clear();
		}
        P_tmp.push_back(0.0);
        P_tmp.push_back(-sqrt(3.0)*2.0/3.0);
        Points.push_back(P_tmp);
        P_tmp.clear();


/**
 * bspline
*/
        curve_spline C(Points, 1, 3);
        C.cal();
        std::vector<std::vector<double> > ans1 = C.Get_Point();
    
        fout1 << "n = " << point_Num[i] << std::endl;
        for (int j = 0; j < ans1.size(); j++)
		{
            fout1 << "part " << j+1 << std::endl;
            for (int k = 0; k < ans1[j].size() - 1; k++)
		    {
                fout1 << ans1[j][k] << ", ";
		    }
            fout1 << ans1[j][ans1[j].size() - 1] <<std::endl;
		}

/**
 * pp-form
*/

        curve_spline D(Points, 2, 3);
        D.cal();
        std::vector<std::vector<double> > ans2 = D.Get_Point();
    
        fout2 << "n = " << point_Num[i] << std::endl;
        for (int j = 0; j < ans2.size(); j++)
		{
            fout2 << "part " << j+1 << std::endl;
            for (int k = 0; k < ans2[j].size() - 1; k++)
		    {
                fout2 << ans2[j][k] << ", ";
		    }
            fout2 << ans2[j][ans2[j].size() - 1] <<std::endl;
		}
	}

    fout1.close();
    fout2.close();

    return 0;
}

